home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / usenet / volume11 / tinymud2 / part08 < prev    next >
Encoding:
Internet Message Format  |  1990-08-10  |  54.7 KB

  1. Path: uunet!zephyr.ens.tek.com!tekred!saab!billr
  2. From: billr@saab.CNA.TEK.COM (Bill Randle)
  3. Newsgroups: comp.sources.games
  4. Subject: v11i012:  tinymud2 - user-extendible multi-user adventure (v1.5.4), Part08/10
  5. Message-ID: <6057@tekred.CNA.TEK.COM>
  6. Date: 30 Jul 90 16:46:25 GMT
  7. Sender: news@tekred.CNA.TEK.COM
  8. Lines: 2286
  9. Approved: billr@saab.CNA.TEK.COM
  10.  
  11. Submitted-by: James Aspnes <asp@cs.cmu.edu>
  12. Posting-number: Volume 11, Issue 12
  13. Archive-name: tinymud2/Part08
  14. Supersedes: tinymud: Volume 8, Issue 80-83
  15.  
  16.  
  17.  
  18. #! /bin/sh
  19. # This is a shell archive.  Remove anything before this line, then unpack
  20. # it by saving it into a file and typing "sh file".  To overwrite existing
  21. # files, type "sh file -c".  You can also feed this as standard input via
  22. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  23. # will see the following message at the end:
  24. #        "End of archive 8 (of 10)."
  25. # Contents:  conc.c dump.c extract.c minimal.db oldinterface.c
  26. # Wrapped by billr@saab on Fri Jul 27 15:27:49 1990
  27. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  28. if test -f 'conc.c' -a "${1}" != "-c" ; then 
  29.   echo shar: Will not clobber existing file \"'conc.c'\"
  30. else
  31. echo shar: Extracting \"'conc.c'\" \(11809 characters\)
  32. sed "s/^X//" >'conc.c' <<'END_OF_FILE'
  33. X/* tinyMUD port concentrator by Robert Hood */
  34. X/* Revision 2.0 */
  35. X
  36. X#include <stdio.h>
  37. X#include <signal.h>
  38. X#include <sys/param.h>
  39. X#include <sys/types.h>
  40. X#include <sys/socket.h>
  41. X#include <netinet/in.h>
  42. X#include <sys/time.h>
  43. X#include <sys/errno.h>
  44. X#include <fcntl.h>
  45. X#include <netdb.h>
  46. X#include "config.h"
  47. X
  48. Xvoid            queue_message(int port, char *data, int len);
  49. Xvoid            writelog(const char *fmt,...);
  50. X
  51. X#define BUFLEN 65536
  52. X#define CONC_MESSAGE "[ Connected to the TinyMUD port concentrator ]\n"
  53. X#define PANIC_MESSAGE "\nGoing Down - Bye!\n"
  54. X
  55. Xstruct message
  56. X{
  57. X  char           *data;
  58. X  short           len;
  59. X  struct message *next;
  60. X};
  61. X
  62. Xstruct conc_list
  63. X{
  64. X  char            status;
  65. X
  66. X  /*
  67. X   * Status: 0 = Not connected 1 = Connected 2 = Disconnecting (waiting till
  68. X   * queue is empty) 
  69. X   */
  70. X  struct message *first, *last;
  71. X}              *clist;
  72. X
  73. Xint             mud_sock;
  74. Xint             sock;
  75. Xint             pid;
  76. X
  77. Xint             port = TINYPORT;
  78. Xint             intport = INTERNAL_PORT;
  79. Xint             clvl = 1;
  80. X
  81. Xmain(argc, argv)
  82. X  int             argc;
  83. X  char           *argv[];
  84. X{
  85. X  int             l;
  86. X
  87. X  if (argc > 1)
  88. X    port = atoi(argv[1]);
  89. X  if (argc > 2)
  90. X    intport = atoi(argv[2]);
  91. X  if (argc > 3)
  92. X    clvl = atoi(argv[3]);
  93. X
  94. X  signal(SIGPIPE, SIG_IGN);           /* Ignore I/O signals */
  95. X  for (l = 3; l < NOFILE; ++l)           /* Close all files from last process */
  96. X    close(l);                   /* except stdin, stdout, stderr */
  97. X  pid = 1;
  98. X  connect_mud();               /* Connect to interface.c */
  99. X  setup();                   /* Setup listen port */
  100. X  mainloop();                   /* main loop */
  101. X}
  102. X
  103. Xconnect_mud()
  104. X{
  105. X  int             temp;
  106. X  struct sockaddr_in sin;
  107. X
  108. X  mud_sock = 0;
  109. X  while (mud_sock == 0)
  110. X  {
  111. X    mud_sock = socket(AF_INET, SOCK_STREAM, 0);
  112. X    if (mud_sock < 0)
  113. X    {
  114. X      perror("socket");
  115. X      mud_sock = 0;
  116. X    } else
  117. X    {
  118. X      temp = 1;
  119. X      setsockopt(mud_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&temp, sizeof(temp));
  120. X      sin.sin_family = AF_INET;
  121. X      sin.sin_port = htons(intport);
  122. X      sin.sin_addr.s_addr = htonl(0x7F000001);
  123. X      temp = connect(mud_sock, (struct sockaddr *) & sin, sizeof(sin));
  124. X      if (temp < 0)
  125. X      {
  126. X    perror("connect");
  127. X    close(mud_sock);
  128. X    mud_sock = 0;
  129. X      }
  130. X    }
  131. X    if (mud_sock == 0)
  132. X    {
  133. X      sleep(1);
  134. X      fputs("retrying....\n", stderr);
  135. X    }
  136. X  }
  137. X  if (fcntl(mud_sock, F_SETFL, FNDELAY) == -1)
  138. X  {
  139. X    perror("make_nonblocking: fcntl");
  140. X  }
  141. X  if (fcntl(mud_sock, F_SETFD, 1) == -1)
  142. X  {
  143. X    perror("close on execve: fcntl");
  144. X  }
  145. X#ifdef DEBUG
  146. X  fputs("connected!\n", stderr);
  147. X#endif
  148. X}
  149. X
  150. Xsetup()
  151. X{
  152. X  int             temp;
  153. X  struct sockaddr_in sin;
  154. X
  155. X  sock = socket(AF_INET, SOCK_STREAM, 0);
  156. X  if (sock < 1)
  157. X  {
  158. X    perror("socket");
  159. X    exit(-1);
  160. X  }
  161. X  temp = 1;
  162. X  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&temp, sizeof(temp));
  163. X  sin.sin_family = AF_INET;
  164. X  sin.sin_port = htons(port);
  165. X  sin.sin_addr.s_addr = htonl(INADDR_ANY);
  166. X
  167. X  temp = bind(sock, (struct sockaddr *) & sin, sizeof(sin));
  168. X  if (temp < 0)
  169. X  {
  170. X    perror("bind");
  171. X    exit(1);
  172. X  }
  173. X  temp = listen(sock, 5);
  174. X  if (temp < 0)
  175. X  {
  176. X    perror("listen");
  177. X    exit(1);
  178. X  }
  179. X}
  180. X
  181. Xmainloop()
  182. X{
  183. X  int             found, newsock, lastsock, len, loop;
  184. X  int             accepting, current = 0;
  185. X  int             temp;
  186. X  struct timeval  tv;
  187. X  struct sockaddr_in sin;
  188. X  struct hostent *hent;
  189. X  fd_set          in, out;
  190. X  char           *data;
  191. X  char           *buf, header[4];
  192. X  struct conc_list *cptr;
  193. X  struct message *tmsg;
  194. X  short           templen;
  195. X  char           *mainbuf, *outbuf;
  196. X  int             mainlen, outlen;
  197. X  int             command;
  198. X  int             hlen;
  199. X  char           *hostnm;
  200. X
  201. X  /* Allocate huge buffer */
  202. X  data = (char *)malloc(65536);
  203. X  /* Allocate array, one for each possible socket */
  204. X  clist = (struct conc_list *) malloc(sizeof(struct conc_list) * NOFILE);
  205. X  /* Allocate I/O buffers for main I/O socket */
  206. X  mainbuf = (char *)malloc(BUFLEN);
  207. X  mainlen = 0;
  208. X  outbuf = (char *)malloc(BUFLEN);
  209. X  outlen = 0;
  210. X  if (!data || !clist || !mainbuf || !outbuf)
  211. X  {
  212. X    perror("malloc");
  213. X    exit(1);
  214. X  }
  215. X  /* Init array */
  216. X  for (loop = 0; loop < NOFILE; ++loop)
  217. X  {
  218. X    cptr = &(clist[loop]);
  219. X    cptr->status = 0;
  220. X    cptr->first = 0;
  221. X    cptr->last = 0;
  222. X  }
  223. X
  224. X  /*
  225. X   * Accept connections flag ON accepting = 1; /* lastsock for select() 
  226. X   */
  227. X  lastsock = sock + 1;
  228. X  /* mud_sock has already been established */
  229. X  clist[mud_sock].status = 1;
  230. X  /* Special port # for control messages */
  231. X  clist[0].status = 1;
  232. X  while (1)
  233. X  {
  234. X    if (pid < 0)
  235. X    {
  236. X      pid = vfork();
  237. X    }
  238. X    if (pid == 0)
  239. X    {
  240. X      char            pstr[32], istr[32], cstr[32];
  241. X      sprintf(pstr, "%d", port);
  242. X      sprintf(istr, "%d", intport);
  243. X      sprintf(cstr, "%d", clvl + 1);
  244. X      execlp("concentrate", "conc", pstr, istr, cstr, 0);
  245. X      writelog("CONC %d:ACK!!!!!! exec failed! Exiting...\n", clvl);
  246. X      exit(1);
  247. X      /* Gee...now what? Should I try again? */
  248. X    }
  249. X    /* zero out port selector masks */
  250. X    FD_ZERO(&in);
  251. X    FD_ZERO(&out);
  252. X
  253. X    /* set apropriate bit masks for I/O */
  254. X    if (accepting)
  255. X      FD_SET(sock, &in);
  256. X    for (loop = 1; loop < NOFILE; ++loop)
  257. X    {
  258. X      cptr = &(clist[loop]);
  259. X      if (cptr->status)
  260. X      {
  261. X    FD_SET(loop, &in);
  262. X    if (cptr->first)
  263. X      FD_SET(loop, &out);
  264. X      }
  265. X    }
  266. X    if (outlen > 0)
  267. X      FD_SET(loop, &out);
  268. X
  269. X    /* timeout for select */
  270. X    tv.tv_sec = 1000;
  271. X    tv.tv_usec = 0;
  272. X
  273. X    /* look for ports waiting for I/O */
  274. X    found = select(lastsock, &in, &out, (fd_set *) 0, &tv);
  275. X    /* None found, skip the rest... */
  276. X    if (found < 0)
  277. X      continue;
  278. X    /* New connection? */
  279. X    if (accepting && FD_ISSET(sock, &in))
  280. X    {
  281. X      len = sizeof(sin);
  282. X      newsock = accept(sock, (struct sockaddr *) & sin, &len);
  283. X      /* This limits the # of connections per concentrator */
  284. X      if (newsock >= (NOFILE - 5))
  285. X      {
  286. X    close(sock);
  287. X    accepting = 0;
  288. X    pid = -1;
  289. X      }
  290. X      if (newsock >= lastsock)
  291. X    lastsock = newsock + 1;
  292. X      cptr = &(clist[newsock]);
  293. X      cptr->status = 1;
  294. X      cptr->first = 0;
  295. X      cptr->last = 0;
  296. X      /* set to non-blocking mode */
  297. X      if (fcntl(newsock, F_SETFL, FNDELAY) == -1)
  298. X      {
  299. X    perror("make_nonblocking: fcntl");
  300. X      }
  301. X      /* set to close on execv */
  302. X      if (fcntl(newsock, F_SETFD, 1) == -1)
  303. X      {
  304. X    perror("close on execv: fcntl");
  305. X      }
  306. X      temp = 1;
  307. X      if (setsockopt(newsock, SOL_SOCKET, SO_KEEPALIVE, (char *)&temp,
  308. X             sizeof(temp)) < 0)
  309. X      {
  310. X    perror("keepalive setsockopt");
  311. X      }
  312. X      queue_message(newsock, CONC_MESSAGE, sizeof(CONC_MESSAGE) - 1);
  313. X      /* build control code for connect */
  314. X      data[0] = 0;
  315. X      data[1] = 1;               /* connect */
  316. X      data[2] = newsock;
  317. X      bcopy(&(sin.sin_addr.s_addr), data + 3, 4);
  318. X      hent = gethostbyaddr(&(sin.sin_addr.s_addr),
  319. X               sizeof(sin.sin_addr.s_addr), AF_INET);
  320. X      if (hent)
  321. X    strcpy(data + 7, hent->h_name);
  322. X      else
  323. X    strcpy(data + 7, inet_ntoa(sin.sin_addr.s_addr));
  324. X      queue_message(mud_sock, data, 7 + strlen(data + 7));
  325. X#ifdef DEBUG
  326. X      writelog("CONC %d: USER CONNECT: sock %d, host %s\n", clvl,
  327. X           newsock, data + 7);
  328. X#endif
  329. X    }
  330. X    /* recieve data from ports */
  331. X    for (loop = 0; loop < NOFILE; ++loop)
  332. X    {
  333. X      cptr = &(clist[loop]);
  334. X      if (cptr->status && FD_ISSET(loop, &in))
  335. X      {
  336. X    if (loop == 0)
  337. X    {
  338. X    } else
  339. X    if (loop == mud_sock)
  340. X    {
  341. X      if (mainlen < BUFLEN)
  342. X      {
  343. X        len = recv(loop, mainbuf + mainlen,
  344. X               BUFLEN - mainlen, 0);
  345. X        if (len <= 0)
  346. X        {
  347. X          /* This is quite useless, but what else am I supposed to do? */
  348. X          writelog("CONC %d: Lost Connection\n", clvl);
  349. X          panic();
  350. X        }
  351. X        mainlen += len;
  352. X      }
  353. X      while (mainlen > 2)
  354. X      {
  355. X        bcopy(mainbuf, &templen, 2);
  356. X        if (mainlen >= (templen + 2))
  357. X        {
  358. X          queue_message(*(mainbuf + 2), mainbuf + 3,
  359. X                templen - 1);
  360. X          mainlen = mainlen - templen - 2;
  361. X          bcopy(mainbuf + templen + 2, mainbuf, mainlen);
  362. X        } else
  363. X          break;
  364. X      }
  365. X    } else
  366. X    {
  367. X      /* data + 1 so we can add port later w/o a bcopy */
  368. X      len = recv(loop, data + 1, 65530, 0);
  369. X      if (len == 0)
  370. X      {
  371. X        disconnect(loop);
  372. X      } else
  373. X      if (len < 0)
  374. X      {
  375. X        /* Hmm..... */
  376. X        writelog("CONC %d: recv: %s\n", clvl, strerror(errno));
  377. X      } else
  378. X      {
  379. X        /* Add the port # to the data, and send it to interface.c */
  380. X        data[0] = loop;
  381. X        queue_message(mud_sock, data, len + 1);
  382. X      }
  383. X    }
  384. X      }
  385. X    }
  386. X    /* Handle output */
  387. X    for (loop = 0; loop < NOFILE; ++loop)
  388. X    {
  389. X      cptr = &(clist[loop]);
  390. X      if ((loop == 0) && (cptr->first))
  391. X      {
  392. X    command = *(cptr->first->data);
  393. X    switch (command)
  394. X    {
  395. X    case 2:               /* disconnect */
  396. X      if (clist[*(cptr->first->data + 1)].status)
  397. X        clist[*(cptr->first->data + 1)].status = 2;
  398. X      else
  399. X        writelog("CONC %d: Recieved dissconnect for unknown user\n", clvl);
  400. X      break;
  401. X    default:
  402. X      writelog("CONC %d: Recieved unknown command %d\n", clvl, command);
  403. X      break;
  404. X    }
  405. X    free(cptr->first->data);
  406. X    tmsg = cptr->first;
  407. X    cptr->first = cptr->first->next;
  408. X    free(tmsg);
  409. X    if (!cptr->first)
  410. X      cptr->last = 0;
  411. X      } else
  412. X    if ((loop == mud_sock) && FD_ISSET(mud_sock, &out) &&
  413. X        ((cptr->first) || (outlen > 0)))
  414. X      {
  415. X    while ((cptr->first) &&
  416. X           ((BUFLEN - outlen) > (cptr->first->len + 2)))
  417. X    {
  418. X      templen = cptr->first->len;
  419. X      bcopy(&(templen), outbuf + outlen, 2);
  420. X      bcopy(cptr->first->data, outbuf + outlen + 2, templen);
  421. X      outlen += templen + 2;
  422. X      free(cptr->first->data);
  423. X      tmsg = cptr->first;
  424. X      cptr->first = cptr->first->next;
  425. X      free(tmsg);
  426. X      if (!cptr->first)
  427. X        cptr->last = 0;
  428. X    }
  429. X
  430. X    if (outlen)
  431. X    {
  432. X      len = send(mud_sock, outbuf, outlen, 0);
  433. X      if (len > 0)
  434. X      {
  435. X        outlen -= len;
  436. X        bcopy(outbuf + len, outbuf, outlen);
  437. X      }
  438. X      else
  439. X      {
  440. X        panic();
  441. X      }
  442. X    }
  443. X      } else
  444. X      if (FD_ISSET(loop, &out) && (cptr->first))
  445. X      {
  446. X    len = send(loop, cptr->first->data, cptr->first->len, 0);
  447. X    free(cptr->first->data);
  448. X    tmsg = cptr->first;
  449. X    cptr->first = cptr->first->next;
  450. X    free(tmsg);
  451. X    if (!cptr->first)
  452. X      cptr->last = 0;
  453. X      }
  454. X      /* Test for pending disconnect */
  455. X      else
  456. X      if ((cptr->status == 2) && (cptr->first == 0))
  457. X      {
  458. X    cptr->status = 0;
  459. X    shutdown(loop, 0);
  460. X    close(loop);
  461. X      }
  462. X    }
  463. X    /* Test for emptyness */
  464. X    if (!accepting)
  465. X    {
  466. X      for (loop = mud_sock + 1; loop < NOFILE; ++loop)
  467. X    if (clist[loop].status)
  468. X      break;
  469. X      if (loop == NOFILE)
  470. X    exit(0);
  471. X    }
  472. X  }
  473. X}
  474. X
  475. X/* Properly disconnect a user */
  476. Xdisconnect(user)
  477. X  int             user;
  478. X{
  479. X  char            header[4];
  480. X
  481. X  /* make control message for disconnect */
  482. X  header[0] = 0;
  483. X  header[1] = 2;               /* disconnect code */
  484. X  header[2] = user;
  485. X  queue_message(mud_sock, header, 3);
  486. X
  487. X  /* shutdown this socket */
  488. X  clist[user].status = 0;
  489. X  close(user);
  490. X#ifdef DEBUG
  491. X  writelog("CONC %d: USER DISCONNECT: %d\n", clvl, user);
  492. X#endif
  493. X}
  494. X
  495. Xvoid            queue_message(int port, char *data, int len)
  496. X{
  497. X  struct message *ptr;
  498. X
  499. X  ptr = (struct message *) malloc(sizeof(struct message));
  500. X  ptr->data = (char *)malloc(len);
  501. X  ptr->len = len;
  502. X  bcopy(data, ptr->data, len);
  503. X  ptr->next = 0;
  504. X  if (clist[port].last == 0)
  505. X    clist[port].first = ptr;
  506. X  else
  507. X    (clist[port].last)->next = ptr;
  508. X  clist[port].last = ptr;
  509. X}
  510. X
  511. X/* Kill off all connections quickly */
  512. Xpanic()
  513. X{
  514. X  int             loop;
  515. X
  516. X  for (loop = 1; loop < NOFILE; ++loop)
  517. X  {
  518. X    if (clist[loop].status)
  519. X    {
  520. X      send(loop, PANIC_MESSAGE, sizeof(PANIC_MESSAGE), 0);
  521. X      shutdown(loop, 0);
  522. X      close(loop);
  523. X    }
  524. X  }
  525. X  exit(1);
  526. X}
  527. X
  528. X/* Modified to send stuff to the main server for logging */
  529. Xvoid            writelog(const char *fmt,...)
  530. X{
  531. X  va_list         list;
  532. X  struct tm      *tm;
  533. X  long            t;
  534. X  char            buffer[2048];
  535. X
  536. X  va_start(list, fmt);
  537. X  vsprintf(buffer + 2, fmt, list);
  538. X  buffer[0] = 0;
  539. X  buffer[1] = 4;               /* remote log command */
  540. X  queue_message(mud_sock, buffer, strlen(buffer + 2) + 2);
  541. X  va_end(list);
  542. X}
  543. END_OF_FILE
  544. if test 11809 -ne `wc -c <'conc.c'`; then
  545.     echo shar: \"'conc.c'\" unpacked with wrong size!
  546. fi
  547. # end of 'conc.c'
  548. fi
  549. if test -f 'dump.c' -a "${1}" != "-c" ; then 
  550.   echo shar: Will not clobber existing file \"'dump.c'\"
  551. else
  552. echo shar: Extracting \"'dump.c'\" \(3229 characters\)
  553. sed "s/^X//" >'dump.c' <<'END_OF_FILE'
  554. X#include "copyright.h"
  555. X
  556. X#include <stdio.h>
  557. X
  558. X#include "db.h"
  559. X
  560. X#ifndef COMPRESS
  561. X#define uncompress(x) (x)
  562. X#else
  563. Xconst char *uncompress(const char *s);
  564. X#endif /* COMPRESS */
  565. X
  566. Xconst char *unparse_object(dbref player, dbref loc);
  567. X
  568. X/* in a dump, you can see everything */
  569. Xint can_link_to(dbref who, object_flag_type what, dbref where)
  570. X{
  571. X    return 1;
  572. X}
  573. X
  574. Xint controls(dbref who, dbref what)
  575. X{
  576. X    return 1;
  577. X}
  578. X
  579. Xvoid main(int argc, char **argv)
  580. X{
  581. X    struct object *o;
  582. X    dbref owner;
  583. X    dbref thing;
  584. X
  585. X    if(argc < 1) {
  586. X    fprintf(stderr, "Usage: %s [owner]\n", *argv);
  587. X    exit(1);
  588. X    }
  589. X    
  590. X    if(argc >= 2) {
  591. X    owner = atol(argv[1]);
  592. X    } else {
  593. X    owner = NOTHING;
  594. X    }
  595. X
  596. X    if(db_read(stdin) < 0) {
  597. X    fprintf(stderr, "%s: bad input\n", argv[0]);
  598. X    exit(5);
  599. X    }
  600. X
  601. X    for(o = db; o < db+db_top; o++) {
  602. X    /* don't show exits separately */
  603. X    if((o->flags & TYPE_MASK) == TYPE_EXIT) continue;
  604. X
  605. X    /* don't show it if it isn't owned by the right player */
  606. X    if(owner != NOTHING && o->owner != owner) continue;
  607. X
  608. X    printf("#%d: %s [%s] at %s Pennies: %d Type: ",
  609. X           o - db, o->name, db[o->owner].name,
  610. X           unparse_object(owner, o->location),
  611. X           o->pennies);
  612. X    switch(o->flags & TYPE_MASK) {
  613. X      case TYPE_ROOM:
  614. X        printf("Room");
  615. X        break;
  616. X      case TYPE_EXIT:
  617. X        printf("Exit");
  618. X        break;
  619. X      case TYPE_THING:
  620. X        printf("Thing");
  621. X        break;
  622. X      case TYPE_PLAYER:
  623. X        printf("Player");
  624. X        break;
  625. X      default:
  626. X        printf("***UNKNOWN TYPE***");
  627. X        break;
  628. X    }
  629. X
  630. X    /* handle flags */
  631. X    putchar(' ');
  632. X    if(o->flags & ~TYPE_MASK) {
  633. X        printf("Flags: ");
  634. X        if(o->flags & LINK_OK) printf("LINK_OK ");
  635. X        if(o->flags & DARK) printf("DARK ");
  636. X        if(o->flags & STICKY) printf("STICKY ");
  637. X        if(o->flags & WIZARD) printf("WIZARD ");
  638. X        if(o->flags & TEMPLE) printf("TEMPLE ");
  639. X#ifdef RESTRICTED_BUILDING
  640. X        if(o->flags & BUILDER) printf("BUILDER ");
  641. X#endif /* RESTRICTED_BUILDING */
  642. X    }
  643. X    putchar('\n');
  644. X           
  645. X    if(o->key != TRUE_BOOLEXP) printf("KEY: %s\n",
  646. X                      unparse_boolexp(owner, o->key));
  647. X    if(o->description) {
  648. X        puts("Description:");
  649. X        puts(uncompress(o->description));
  650. X    }
  651. X    if(o->succ_message) {
  652. X        puts("Success Message:");
  653. X        puts(uncompress(o->succ_message));
  654. X    }
  655. X    if(o->fail_message) {
  656. X        puts("Fail Message:");
  657. X        puts(uncompress(o->fail_message));
  658. X    }
  659. X    if(o->ofail) {
  660. X        puts("Other Fail Message:");
  661. X        puts(uncompress(o->ofail));
  662. X    }
  663. X    if(o->osuccess) {
  664. X        puts("Other Success Message:");
  665. X        puts(uncompress(o->osuccess));
  666. X    }
  667. X    if(o->contents != NOTHING) {
  668. X        puts("Contents:");
  669. X        DOLIST(thing, o->contents) {
  670. X        /* dump thing description */
  671. X        putchar(' ');
  672. X        puts(unparse_object(owner, thing));
  673. X        }
  674. X    }
  675. X    if(o->exits != NOTHING) {
  676. X        if((o->flags & TYPE_MASK) == TYPE_ROOM) {
  677. X        puts("Exits:");
  678. X        DOLIST(thing, o->exits) {
  679. X            printf(" %s", unparse_object(owner, thing));
  680. X            if(db[thing].key != TRUE_BOOLEXP) {
  681. X            printf(" KEY: %s",
  682. X                   unparse_boolexp(owner, db[thing].key));
  683. X            }
  684. X            if(db[thing].location != NOTHING) {
  685. X            printf(" => %s\n",
  686. X                   unparse_object(owner, db[thing].location));
  687. X            } else {
  688. X            puts(" ***OPEN***");
  689. X            }
  690. X        }
  691. X        } else {
  692. X        printf("Home: %s\n", unparse_object(owner, o->exits));
  693. X        }
  694. X    }
  695. X    putchar('\n');
  696. X    }
  697. X
  698. X    exit(0);
  699. X}
  700. END_OF_FILE
  701. if test 3229 -ne `wc -c <'dump.c'`; then
  702.     echo shar: \"'dump.c'\" unpacked with wrong size!
  703. fi
  704. # end of 'dump.c'
  705. fi
  706. if test -f 'extract.c' -a "${1}" != "-c" ; then 
  707.   echo shar: Will not clobber existing file \"'extract.c'\"
  708. else
  709. echo shar: Extracting \"'extract.c'\" \(10634 characters\)
  710. sed "s/^X//" >'extract.c' <<'END_OF_FILE'
  711. X#include "copyright.h"
  712. X
  713. X#include <stdio.h>
  714. X#include <ctype.h>
  715. X#include <sys/param.h>
  716. X
  717. X#include "db.h"
  718. X
  719. Xstatic int include_all = 0;    /* include everything unless specified */
  720. Xstatic int keep_players = 0;    /* keep all players */
  721. Xstatic int safe_below = 1;    /* Keep everything <= safe_below */
  722. Xstatic int safe_above = 2e9;    /* Keep everything >= safe_above */
  723. Xstatic int reachable = 0;    /* Only keep rooms reachable from #0 */
  724. Xstatic int norecycle = 0;    /* Exclude things in recycling center */
  725. Xstatic int inbuild = 0;        /* True when in main nuild_trans loop */
  726. Xstatic int recycling_center = 0;/* Room number home("Recycler") */
  727. X
  728. X# define REACH_FLAG 0x40000000
  729. X# define REACHABLE(X) (db[X].flags & REACH_FLAG)
  730. X# define SET_REACHABLE(X) (db[X].flags |= REACH_FLAG)
  731. X
  732. Xstatic dbref included[NCARGS+1];
  733. Xstatic dbref excluded[NCARGS+1];
  734. X
  735. Xstatic dbref *trans;        /* translation vector */
  736. X
  737. X#define DEFAULT_LOCATION (0)
  738. X#define DEFAULT_OWNER (1)
  739. X
  740. Xstatic int isok(dbref);
  741. X
  742. X/* returns 1 if object is specifically excluded */
  743. Xstatic int is_excluded(dbref x)
  744. X{
  745. X    int i;
  746. X
  747. X    if(x == NOTHING) return 0; /* Don't exclude nothing */
  748. X
  749. X    /* check that it isn't excluded */
  750. X    for(i = 0; excluded[i] != NOTHING; i++) {
  751. X    if(excluded[i] == x) return 1; /* always exclude specifics */
  752. X        if(excluded[i] == db[x].owner) return 1;
  753. X    }
  754. X
  755. X    return (0);
  756. X}
  757. X
  758. X/* returns 1 if it is not excluded */
  759. Xstatic int not_excluded(dbref x)
  760. X{
  761. X    int i;
  762. X
  763. X    if(x == NOTHING) return 1; /* Don't exclude nothing */
  764. X
  765. X    /* check that it isn't excluded */
  766. X    for(i = 0; excluded[i] != NOTHING; i++) {
  767. X    if(excluded[i] == x) return 0; /* always exclude specifics */
  768. X        if(excluded[i] == db[x].owner) return 0;
  769. X    }
  770. X
  771. X    /* if it's an exit, check that its destination is ok */
  772. X    if(Typeof(x) == TYPE_EXIT && db[x].location >= 0) {
  773. X    return isok(db[x].location);
  774. X    } else {
  775. X    return 1;
  776. X    }
  777. X}
  778. X
  779. X/* returns 1 if it should be included in translation vector */
  780. Xstatic int isok(dbref x)
  781. X{
  782. X    int i;
  783. X
  784. X    if(x == DEFAULT_OWNER || x == DEFAULT_LOCATION) return 1;
  785. X    if(x == NOTHING) return 1;
  786. X    
  787. X    for(i = 0; included[i] != NOTHING; i++) {
  788. X    if(included[i] == x) return 1; /* always get specific ones */
  789. X    
  790. X    if(reachable && Typeof(x) == TYPE_ROOM && !REACHABLE(x))
  791. X    { 
  792. X# ifdef DEBUG
  793. X      if (inbuild)
  794. X        fprintf (stderr, "Excluding %s(%dR), not reachable\n", 
  795. X             db[x].name, x);
  796. X# endif
  797. X          return 0;
  798. X    }
  799. X    
  800. X    if(norecycle && db[x].location == recycling_center) return 0;
  801. X
  802. X    if(included[i] == db[x].owner 
  803. X       || (x <= safe_below || x >= safe_above)
  804. X       || keep_players && Typeof(x) == TYPE_PLAYER) {
  805. X        return not_excluded(x);
  806. X    }
  807. X    }
  808. X
  809. X    /* not in the list, can only get it if include_all is on */
  810. X    /* or it's owned by DEFAULT_OWNER */
  811. X    return (include_all && not_excluded(x));
  812. X}
  813. X
  814. Xstatic void build_trans(void)
  815. X{
  816. X    dbref i;
  817. X    dbref val;
  818. X
  819. X    if((trans = (dbref *) malloc(sizeof(dbref) * db_top)) == 0) {
  820. X    abort();
  821. X    }
  822. X    
  823. X    inbuild++;
  824. X
  825. X    val = 0;
  826. X    for(i = 0; i < db_top; i++) {
  827. X    if(isok(i)) {
  828. X        trans[i] = val++;
  829. X    } else {
  830. X        trans[i] = NOTHING;
  831. X    }
  832. X    }
  833. X    
  834. X    inbuild--;
  835. X}
  836. X
  837. Xstatic dbref translate(dbref x)
  838. X{
  839. X    if(x == NOTHING || x == HOME) {
  840. X    return(x);
  841. X    } else {
  842. X    return(trans[x]);
  843. X    }
  844. X}
  845. X
  846. X/* TRUE_BOOLEXP means throw this argument out */
  847. X/* even on OR; it's effectively a null boolexp */
  848. X/* NOTE: this doesn't free anything, it just munges it up */
  849. Xstatic struct boolexp *translate_boolexp(struct boolexp *exp)
  850. X{
  851. X    struct boolexp *s1;
  852. X    struct boolexp *s2;
  853. X
  854. X    if(exp == TRUE_BOOLEXP) {
  855. X    return TRUE_BOOLEXP;
  856. X    } else {
  857. X    switch(exp->type) {
  858. X      case BOOLEXP_NOT:
  859. X        s1 = translate_boolexp(exp->sub1);
  860. X        if(s1 == TRUE_BOOLEXP) {
  861. X        return TRUE_BOOLEXP;
  862. X        } else {
  863. X        exp->sub1 = s1;
  864. X        return exp;
  865. X        }
  866. X        /* break; */
  867. X      case BOOLEXP_AND:
  868. X      case BOOLEXP_OR:
  869. X        s1 = translate_boolexp(exp->sub1);
  870. X        s2 = translate_boolexp(exp->sub2);
  871. X        if(s1 == TRUE_BOOLEXP && s2 == TRUE_BOOLEXP) {
  872. X        /* nothing left */
  873. X        return TRUE_BOOLEXP;
  874. X        } else if(s1 == TRUE_BOOLEXP && s2 != TRUE_BOOLEXP) {
  875. X        /* s2 is all that is left */
  876. X        return s2;
  877. X        } else if(s1 != TRUE_BOOLEXP && s2 == TRUE_BOOLEXP) {
  878. X        /* s1 is all that is left */
  879. X        return s1;
  880. X        } else {
  881. X        exp->sub1 = s1;
  882. X        exp->sub2 = s2;
  883. X        return exp;
  884. X        }
  885. X        /* break; */
  886. X      case BOOLEXP_CONST:
  887. X        exp->thing = translate(exp->thing);
  888. X        if(exp->thing == NOTHING) {
  889. X        return TRUE_BOOLEXP;
  890. X        } else {
  891. X        return exp;
  892. X        }
  893. X        /* break; */
  894. X      default:
  895. X        abort();        /* bad boolexp type, we lose */
  896. X        return TRUE_BOOLEXP;
  897. X    }
  898. X    }
  899. X}
  900. X
  901. Xstatic int ok(dbref x)
  902. X{
  903. X    if(x == NOTHING || x == HOME) {
  904. X    return 1;
  905. X    } else {
  906. X    return trans[x] != NOTHING;
  907. X    }
  908. X}
  909. X
  910. Xstatic void check_bad_exits(dbref x)
  911. X{
  912. X    dbref e;
  913. X
  914. X    if(Typeof(x) == TYPE_ROOM && !isok(x)) {
  915. X    /* mark all exits as excluded */
  916. X    DOLIST(e, db[x].exits) {
  917. X        trans[e] = NOTHING;
  918. X    }
  919. X    }
  920. X}
  921. X
  922. Xstatic void check_owner(dbref x)
  923. X{
  924. X    if(ok(x) && !ok(db[x].owner)) {
  925. X    db[x].owner = DEFAULT_OWNER;
  926. X    }
  927. X}
  928. X
  929. Xstatic void check_location(dbref x)
  930. X{
  931. X    dbref loc;
  932. X    dbref newloc;
  933. X
  934. X    if(ok(x) && (Typeof(x) == TYPE_THING || Typeof(x) == TYPE_PLAYER)
  935. X       && !ok(loc = db[x].location)) {
  936. X    /* move it to home or DEFAULT_LOCATION */
  937. X    if(ok(db[x].exits)) {
  938. X        newloc = db[x].exits; /* home */
  939. X    } else {
  940. X        newloc = DEFAULT_LOCATION;
  941. X    }
  942. X    db[loc].contents = remove_first(db[loc].contents, x);
  943. X    PUSH(x, db[newloc].contents);
  944. X    db[x].location = newloc;
  945. X    }
  946. X}
  947. X
  948. Xstatic void check_next(dbref x)
  949. X{
  950. X    dbref next;
  951. X
  952. X    if(ok(x)) {
  953. X    while(!ok(next = db[x].next)) db[x].next = db[next].next;
  954. X    }
  955. X}
  956. X
  957. Xstatic void check_contents(dbref x)
  958. X{
  959. X    dbref c;
  960. X
  961. X    if(ok(x)) {
  962. X    while(!ok(c = db[x].contents)) db[x].contents = db[c].next;
  963. X    }
  964. X}
  965. X
  966. X/* also updates home */
  967. X/* MUST BE CALLED AFTER check_owner! */
  968. Xstatic void check_exits(dbref x)
  969. X{
  970. X    dbref e;
  971. X
  972. X    if(ok(x) && !ok(e = db[x].exits)) {
  973. X    switch(Typeof(x)) {
  974. X      case TYPE_ROOM:
  975. X        while(!ok(e = db[x].exits)) db[x].exits = db[e].next;
  976. X        break;
  977. X      case TYPE_PLAYER:
  978. X      case TYPE_THING:
  979. X        if(ok(db[db[x].owner].exits)) {
  980. X        /* set it to owner's home */
  981. X        db[x].exits = db[db[x].owner].exits; /* home */
  982. X        } else {
  983. X        /* set it to DEFAULT_LOCATION */
  984. X        db[x].exits = DEFAULT_LOCATION; /* home */
  985. X        }
  986. X        break;
  987. X    }
  988. X    }
  989. X}
  990. X
  991. Xstatic void do_write(void)
  992. X{
  993. X    dbref i;
  994. X    dbref kludge;
  995. X
  996. X    /* this is braindamaged */
  997. X    /* we have to rebuild the translation map */
  998. X    /* because part of it may have gotten nuked in check_bad_exits */
  999. X    for(i = 0, kludge = 0; i < db_top; i++) {
  1000. X    if(trans[i] != NOTHING) trans[i] = kludge++;
  1001. X    }
  1002. X
  1003. X    for(i = 0; i < db_top; i++) {
  1004. X    if(ok(i)) {
  1005. X        /* translate all object pointers */
  1006. X        db[i].location = translate(db[i].location);
  1007. X        db[i].contents = translate(db[i].contents);
  1008. X        db[i].exits = translate(db[i].exits);
  1009. X        db[i].next = translate(db[i].next);
  1010. X        db[i].key = translate_boolexp(db[i].key);
  1011. X        db[i].owner = translate(db[i].owner);
  1012. X
  1013. X        /* write it out */
  1014. X        printf("#%d\n", translate(i));
  1015. X        db_write_object(stdout, i);
  1016. X    }
  1017. X    }
  1018. X    puts("***END OF DUMP***");
  1019. X}
  1020. X
  1021. Xint reach_lvl = 0;
  1022. X
  1023. Xmake_reachable (dbref x)
  1024. X{   dbref e, r;
  1025. X    int i;
  1026. X    
  1027. X    if (Typeof(x) != TYPE_ROOM || is_excluded(x)) return;
  1028. X
  1029. X    reach_lvl++;
  1030. X
  1031. X    SET_REACHABLE(x);
  1032. X
  1033. X#ifdef DEBUG
  1034. X    for (i=0; i<reach_lvl; i++ ) fputc (' ', stderr);
  1035. X    fprintf (stderr, "Set %s(%dR) reachable.\n", db[x].name, x);
  1036. X#endif
  1037. X
  1038. X    DOLIST(e, db[x].exits) {
  1039. X    r = db[e].location;
  1040. X
  1041. X    if (r < 0) continue;
  1042. X    if (is_excluded(r)) continue;
  1043. X        if (is_excluded(e)) continue;
  1044. X    if (!REACHABLE(r)) make_reachable(r);
  1045. X    }
  1046. X
  1047. X    reach_lvl--;
  1048. X}
  1049. X
  1050. Xvoid main(int argc, char **argv)
  1051. X{
  1052. X    dbref i;
  1053. X    int top_in;
  1054. X    int top_ex;
  1055. X    char *arg0;
  1056. X
  1057. X    top_in = 0;
  1058. X    top_ex = 0;
  1059. X
  1060. X    /* Load database */
  1061. X    if(db_read(stdin) < 0) {
  1062. X    fputs("Database load failed!\n", stderr);
  1063. X    exit(1);
  1064. X    } 
  1065. X
  1066. X    fputs("Done loading database...\n", stderr);
  1067. X
  1068. X
  1069. X    /* now parse args */
  1070. X    arg0 = *argv;
  1071. X    for (argv++, argc--; argc > 0; argv++, argc--) {
  1072. X    if (isdigit (**argv) || **argv == '-' && isdigit ((*argv)[1])) {
  1073. X        i = atol(*argv);
  1074. X    } else if (**argv == '+' && isdigit ((*argv)[1])) {
  1075. X        i = atol(*argv+1);
  1076. X    } else if (**argv == 'b' && isdigit ((*argv)[1])) {
  1077. X        safe_below = atol(*argv+1);
  1078. X        fprintf (stderr, "Including all objects %d and below\n",
  1079. X                 safe_below);
  1080. X    } else if (**argv == 'a' && isdigit ((*argv)[1])) {
  1081. X        safe_above = atol(*argv+1);
  1082. X        fprintf (stderr, "Including all objects %d and above\n",
  1083. X                 safe_above);
  1084. X    } else if (!strcmp(*argv, "all")) {
  1085. X        include_all = 1;
  1086. X    } else if (!strcmp(*argv, "reachable")) {
  1087. X        reachable = 1;
  1088. X    } else if (!strcmp(*argv, "players")) {
  1089. X        keep_players = 1;
  1090. X    } else if (!strcmp(*argv, "norecycle")) {
  1091. X        norecycle = 1;
  1092. X    } else if (**argv == '-' &&
  1093. X               (i = lookup_player (*argv+1)) != 0) {
  1094. X        fprintf (stderr, "Excluding player %s(%d)\n",
  1095. X             db[i].name, i);
  1096. X        i = -i;
  1097. X    } else if (**argv != '-' &&
  1098. X                   (i = lookup_player (*argv)) != NOTHING) {
  1099. X        fprintf (stderr, "Including player %s(%d)\n",
  1100. X             db[i].name, i);
  1101. X    } else {
  1102. X        fprintf(stderr, "%s: bogus argument %s\n", arg0, *argv);
  1103. X        continue;
  1104. X    }
  1105. X    
  1106. X    if(i < 0) {
  1107. X        excluded[top_ex++] = -i;
  1108. X    } else {
  1109. X        included[top_in++] = i;
  1110. X    }
  1111. X    }
  1112. X
  1113. X    /* Terminate */
  1114. X    included[top_in++] = NOTHING;
  1115. X    excluded[top_ex++] = NOTHING;
  1116. X
  1117. X    /* Check for reachability from DEFAULT_LOCATION */
  1118. X    if (reachable)
  1119. X    { make_reachable (DEFAULT_LOCATION); 
  1120. X      fputs ("Done marking reachability...\n", stderr); 
  1121. X    }
  1122. X    
  1123. X    /* Find recycler */
  1124. X    if (norecycle && ((i = lookup_player (RECYCLER)) != NOTHING))
  1125. X    { recycling_center = db[i].exits;
  1126. X      if (recycling_center == DEFAULT_LOCATION) norecycle = 0;
  1127. X      else
  1128. X      { fprintf (stderr, "Excluding all players in %s(%d)\n",
  1129. X                db[recycling_center].name, recycling_center);
  1130. X      }
  1131. X    }
  1132. X
  1133. X    /* Build translation table */
  1134. X    build_trans();
  1135. X    fputs("Done building translation table...\n", stderr);
  1136. X
  1137. X    /* Scan everything */
  1138. X    for(i = 0; i < db_top; i++) check_bad_exits(i);
  1139. X    fputs("Done checking bad exits...\n", stderr);
  1140. X
  1141. X    for(i = 0; i < db_top; i++) check_owner(i);
  1142. X    fputs("Done checking owners...\n", stderr);
  1143. X
  1144. X    for(i = 0; i < db_top; i++) check_location(i);
  1145. X    fputs("Done checking locations...\n", stderr);
  1146. X
  1147. X    for(i = 0; i < db_top; i++) check_next(i);
  1148. X    fputs("Done checking next pointers...\n", stderr);
  1149. X
  1150. X    for(i = 0; i < db_top; i++) check_contents(i);
  1151. X    fputs("Done checking contents...\n", stderr);
  1152. X
  1153. X    for(i = 0; i < db_top; i++) check_exits(i);
  1154. X    fputs("Done checking homes and exits...\n", stderr);
  1155. X
  1156. X    do_write();
  1157. X    fputs("Done.\n", stderr);
  1158. X
  1159. X    exit(0);
  1160. X}
  1161. END_OF_FILE
  1162. if test 10634 -ne `wc -c <'extract.c'`; then
  1163.     echo shar: \"'extract.c'\" unpacked with wrong size!
  1164. fi
  1165. # end of 'extract.c'
  1166. fi
  1167. if test -f 'minimal.db' -a "${1}" != "-c" ; then 
  1168.   echo shar: Will not clobber existing file \"'minimal.db'\"
  1169. else
  1170. echo shar: Extracting \"'minimal.db'\" \(197 characters\)
  1171. sed "s/^X//" >'minimal.db' <<'END_OF_FILE'
  1172. X#0
  1173. XRoom Zero
  1174. XYou are in Room Zero.  It's very dark here.
  1175. X-1
  1176. X1
  1177. X-1
  1178. X-1
  1179. X-1
  1180. X
  1181. X
  1182. X
  1183. Xis briefly visible through the mist.
  1184. X1
  1185. X0
  1186. X0
  1187. X
  1188. X#1
  1189. XOne
  1190. XYou see Number One.
  1191. X0
  1192. X-1
  1193. X0
  1194. X-1
  1195. X-1
  1196. X
  1197. X
  1198. X
  1199. X
  1200. X1
  1201. X0
  1202. X19
  1203. Xpotrzebie
  1204. X***END OF DUMP***
  1205. END_OF_FILE
  1206. if test 197 -ne `wc -c <'minimal.db'`; then
  1207.     echo shar: \"'minimal.db'\" unpacked with wrong size!
  1208. fi
  1209. # end of 'minimal.db'
  1210. fi
  1211. if test -f 'oldinterface.c' -a "${1}" != "-c" ; then 
  1212.   echo shar: Will not clobber existing file \"'oldinterface.c'\"
  1213. else
  1214. echo shar: Extracting \"'oldinterface.c'\" \(24677 characters\)
  1215. sed "s/^X//" >'oldinterface.c' <<'END_OF_FILE'
  1216. X#include "copyright.h"
  1217. X
  1218. X#include <stdio.h>
  1219. X#include <sys/types.h>
  1220. X#include <sys/file.h>
  1221. X#include <sys/time.h>
  1222. X#include <signal.h>
  1223. X#include <sys/ioctl.h>
  1224. X#include <sys/wait.h>
  1225. X#include <fcntl.h>
  1226. X#include <sys/errno.h>
  1227. X#include <ctype.h>
  1228. X#include <sys/socket.h>
  1229. X#include <netinet/in.h>
  1230. X#include <netdb.h>
  1231. X
  1232. X#include "db.h"
  1233. X#include "interface.h"
  1234. X#include "config.h"
  1235. X
  1236. Xextern int    errno;
  1237. Xint    shutdown_flag = 0;
  1238. X
  1239. Xstatic const char *connect_fail = "Either that player does not exist, or has a different password.\n";
  1240. X#ifndef REGISTRATION
  1241. Xstatic const char *create_fail = "Either there is already a player with that name, or that name is illegal.\n";
  1242. X#endif REGISTRATION
  1243. Xstatic const char *flushed_message = "<Output Flushed>\n";
  1244. Xstatic const char *shutdown_message = "Going down - Bye\n";
  1245. X
  1246. Xstruct text_block {
  1247. X    int            nchars;
  1248. X    struct text_block    *nxt;
  1249. X    char            *start;
  1250. X    char            *buf;
  1251. X};
  1252. X
  1253. Xstruct text_queue {
  1254. X    struct text_block *head;
  1255. X    struct text_block **tail;
  1256. X};
  1257. X
  1258. Xstruct descriptor_data {
  1259. X        int descriptor;
  1260. X    int connected;
  1261. X    dbref player;
  1262. X    char *output_prefix;
  1263. X    char *output_suffix;
  1264. X    int output_size;
  1265. X    struct text_queue output;
  1266. X    struct text_queue input;
  1267. X    char *raw_input;
  1268. X    char *raw_input_at;
  1269. X    long last_time;
  1270. X    long connected_at;
  1271. X    int quota;
  1272. X    struct sockaddr_in address;
  1273. X    const char *hostname;        /* 5/18/90 - Fuzzy */
  1274. X    struct descriptor_data *next;
  1275. X    struct descriptor_data *prev;
  1276. X} *descriptor_list = 0;
  1277. X
  1278. Xstatic int sock;
  1279. Xstatic int ndescriptors = 0;
  1280. X
  1281. Xvoid process_commands(void);
  1282. Xvoid shovechars(int port);
  1283. Xvoid shutdownsock(struct descriptor_data *d);
  1284. Xstruct descriptor_data *initializesock(int s, struct sockaddr_in *a,
  1285. X                       const char *hostname);
  1286. Xvoid make_nonblocking(int s);
  1287. Xvoid freeqs(struct descriptor_data *d);
  1288. Xvoid welcome_user(struct descriptor_data *d);
  1289. Xvoid do_motd(dbref);
  1290. Xvoid check_connect(struct descriptor_data *d, const char *msg);
  1291. Xvoid close_sockets();
  1292. Xconst char *addrout (long);
  1293. Xvoid dump_users(struct descriptor_data *d, char *user);
  1294. Xvoid set_signals(void);
  1295. Xstruct descriptor_data *new_connection(int sock);
  1296. Xvoid parse_connect (const char *msg, char *command, char *user, char *pass);
  1297. Xvoid set_userstring (char **userstring, const char *command);
  1298. Xint do_command (struct descriptor_data *d, char *command);
  1299. Xchar *strsave (const char *s);
  1300. Xint make_socket(int);
  1301. Xint queue_string(struct descriptor_data *, const char *);
  1302. Xint queue_write(struct descriptor_data *, const char *, int);
  1303. Xint process_output(struct descriptor_data *d);
  1304. Xint process_input(struct descriptor_data *d);
  1305. X#ifdef CONNECT_MESSAGES
  1306. Xvoid announce_connect(dbref);
  1307. Xvoid announce_disconnect(dbref);
  1308. X#endif CONNECT_MESSAGES
  1309. Xchar *time_format_1(long);
  1310. Xchar *time_format_2(long);
  1311. X
  1312. X/* Signal handlers */
  1313. Xint bailout (int, int, struct sigcontext *);
  1314. Xint sigshutdown (int, int, struct sigcontext *);
  1315. X#ifdef DETACH
  1316. Xint logsynch (int, int, struct sigcontext *);
  1317. X#endif DETACH
  1318. X
  1319. Xchar *logfile = LOG_FILE;
  1320. X
  1321. X#define MALLOC(result, type, number) do {            \
  1322. X    if (!((result) = (type *) malloc ((number) * sizeof (type))))    \
  1323. X        panic("Out of memory");                \
  1324. X    } while (0)
  1325. X
  1326. X#define FREE(x) (free((void *) x))
  1327. X
  1328. X#ifndef BOOLEXP_DEBUGGING
  1329. Xvoid main(int argc, char **argv)
  1330. X{
  1331. X    if (argc < 3) {
  1332. X    fprintf(stderr, "Usage: %s infile dumpfile [port [logfile]]\n", *argv);
  1333. X    exit (1);
  1334. X    }
  1335. X
  1336. X    if (argc > 4) logfile = argv[4];
  1337. X
  1338. X    set_signals ();
  1339. X    if (init_game (argv[1], argv[2]) < 0) {
  1340. X    writelog("INIT: Couldn't load %s!\n", argv[1]);
  1341. X    exit (2);
  1342. X    }
  1343. X
  1344. X    /* go do it */
  1345. X    shovechars (argc >= 4 ? atoi (argv[3]) : TINYPORT);
  1346. X    close_sockets ();
  1347. X    dump_database ();
  1348. X    exit (0);
  1349. X}
  1350. X#endif /*BOOLEXP_DEBUGGING*/
  1351. X
  1352. Xvoid set_signals(void)
  1353. X{
  1354. X#ifdef DETACH
  1355. X    int i;
  1356. X
  1357. X    if (fork() != 0) exit(0);
  1358. X
  1359. X    for (i=getdtablesize(); i >= 0; i--)
  1360. X    (void) close(i);
  1361. X
  1362. X    i = open("/dev/tty", O_RDWR, 0);
  1363. X    if (i != -1) {
  1364. X    ioctl(i, TIOCNOTTY, 0);
  1365. X    close(i);
  1366. X    }
  1367. X
  1368. X    freopen(logfile, "a", stderr);
  1369. X    setbuf(stderr, NULL);
  1370. X#endif DETACH    
  1371. X    
  1372. X    /* we don't care about SIGPIPE, we notice it in select() and write() */
  1373. X    signal (SIGPIPE, SIG_IGN);
  1374. X
  1375. X    /* standard termination signals */
  1376. X    signal (SIGINT, (void (*)) sigshutdown);
  1377. X    signal (SIGTERM, (void (*)) sigshutdown);
  1378. X
  1379. X#ifdef DETACH
  1380. X    /* SIGUSR2 synchronizes the log file */
  1381. X    signal (SIGUSR2, (void (*)) logsynch);
  1382. X#else DETACH    
  1383. X    signal (SIGUSR2, (void (*)) bailout);
  1384. X#endif DETACH    
  1385. X
  1386. X    /* catch these because we might as well */
  1387. X    signal (SIGQUIT, (void (*)) bailout);
  1388. X    signal (SIGILL, (void (*)) bailout);
  1389. X    signal (SIGTRAP, (void (*)) bailout);
  1390. X    signal (SIGIOT, (void (*)) bailout);
  1391. X    signal (SIGEMT, (void (*)) bailout);
  1392. X    signal (SIGFPE, (void (*)) bailout);
  1393. X    signal (SIGBUS, (void (*)) bailout);
  1394. X    signal (SIGSEGV, (void (*)) bailout);
  1395. X    signal (SIGSYS, (void (*)) bailout);
  1396. X    signal (SIGXCPU, (void (*)) bailout);
  1397. X    signal (SIGXFSZ, (void (*)) bailout);
  1398. X    signal (SIGVTALRM, (void (*)) bailout);
  1399. X    signal (SIGUSR1, (void (*)) bailout);
  1400. X}
  1401. X
  1402. Xint notify(dbref player, const char *msg)
  1403. X{
  1404. X    struct descriptor_data *d;
  1405. X    int retval = 0;
  1406. X#ifdef COMPRESS
  1407. X    extern const char *uncompress(const char *);
  1408. X
  1409. X    msg = uncompress(msg);
  1410. X#endif /* COMPRESS */
  1411. X
  1412. X    for(d = descriptor_list; d; d = d->next) {
  1413. X    if (d->connected && d->player == player) {
  1414. X        queue_string(d, msg);
  1415. X        queue_write(d, "\n", 1);
  1416. X        retval = 1;
  1417. X    }
  1418. X    }
  1419. X    return(retval);
  1420. X}
  1421. X
  1422. Xstruct timeval timeval_sub(struct timeval now, struct timeval then)
  1423. X{
  1424. X    now.tv_sec -= then.tv_sec;
  1425. X    now.tv_usec -= then.tv_usec;
  1426. X    if (now.tv_usec < 0) {
  1427. X    now.tv_usec += 1000000;
  1428. X    now.tv_sec--;
  1429. X    }
  1430. X    return now;
  1431. X}
  1432. X
  1433. Xint msec_diff(struct timeval now, struct timeval then)
  1434. X{
  1435. X    return ((now.tv_sec - then.tv_sec) * 1000
  1436. X        + (now.tv_usec - then.tv_usec) / 1000);
  1437. X}
  1438. X
  1439. Xstruct timeval msec_add(struct timeval t, int x)
  1440. X{
  1441. X    t.tv_sec += x / 1000;
  1442. X    t.tv_usec += (x % 1000) * 1000;
  1443. X    if (t.tv_usec >= 1000000) {
  1444. X    t.tv_sec += t.tv_usec / 1000000;
  1445. X    t.tv_usec = t.tv_usec % 1000000;
  1446. X    }
  1447. X    return t;
  1448. X}
  1449. X
  1450. Xstruct timeval update_quotas(struct timeval last, struct timeval current)
  1451. X{
  1452. X    int nslices;
  1453. X    struct descriptor_data *d;
  1454. X
  1455. X    nslices = msec_diff (current, last) / COMMAND_TIME_MSEC;
  1456. X
  1457. X    if (nslices > 0) {
  1458. X    for (d = descriptor_list; d; d = d -> next) {
  1459. X        d -> quota += COMMANDS_PER_TIME * nslices;
  1460. X        if (d -> quota > COMMAND_BURST_SIZE)
  1461. X        d -> quota = COMMAND_BURST_SIZE;
  1462. X    }
  1463. X    }
  1464. X    return msec_add (last, nslices * COMMAND_TIME_MSEC);
  1465. X}
  1466. X
  1467. Xvoid shovechars(int port)
  1468. X{
  1469. X    fd_set input_set, output_set;
  1470. X    long now;
  1471. X    struct timeval last_slice, current_time;
  1472. X    struct timeval next_slice;
  1473. X    struct timeval timeout, slice_timeout;
  1474. X    int maxd;
  1475. X    struct descriptor_data *d, *dnext;
  1476. X    struct descriptor_data *newd;
  1477. X    int avail_descriptors;
  1478. X
  1479. X    sock = make_socket (port);
  1480. X    maxd = sock+1;
  1481. X    gettimeofday(&last_slice, (struct timezone *) 0);
  1482. X
  1483. X    avail_descriptors = getdtablesize() - 4;
  1484. X    
  1485. X    while (shutdown_flag == 0) {
  1486. X    gettimeofday(¤t_time, (struct timezone *) 0);
  1487. X    last_slice = update_quotas (last_slice, current_time);
  1488. X
  1489. X    process_commands();
  1490. X
  1491. X    if (shutdown_flag)
  1492. X        break;
  1493. X    timeout.tv_sec = 1000;
  1494. X    timeout.tv_usec = 0;
  1495. X    next_slice = msec_add (last_slice, COMMAND_TIME_MSEC);
  1496. X    slice_timeout = timeval_sub (next_slice, current_time);
  1497. X    
  1498. X    FD_ZERO (&input_set);
  1499. X    FD_ZERO (&output_set);
  1500. X    if (ndescriptors < avail_descriptors)
  1501. X        FD_SET (sock, &input_set);
  1502. X    for (d = descriptor_list; d; d=d->next) {
  1503. X        if (d->input.head)
  1504. X        timeout = slice_timeout;
  1505. X        else
  1506. X        FD_SET (d->descriptor, &input_set);
  1507. X        if (d->output.head)
  1508. X        FD_SET (d->descriptor, &output_set);
  1509. X    }
  1510. X
  1511. X    if (select (maxd, &input_set, &output_set,
  1512. X            (fd_set *) 0, &timeout) < 0) {
  1513. X        if (errno != EINTR) {
  1514. X        perror ("select");
  1515. X        return;
  1516. X        }
  1517. X    } else {
  1518. X        (void) time (&now);
  1519. X        if (FD_ISSET (sock, &input_set)) {
  1520. X        if (!(newd = new_connection (sock))) {
  1521. X            if (errno
  1522. X            && errno != EINTR
  1523. X            && errno != EMFILE
  1524. X            && errno != ENFILE) {
  1525. X            perror ("new_connection");
  1526. X            return;
  1527. X            }
  1528. X        } else {
  1529. X        if (newd->descriptor >= maxd)
  1530. X            maxd = newd->descriptor + 1;
  1531. X        }
  1532. X        }
  1533. X        for (d = descriptor_list; d; d = dnext) {
  1534. X        dnext = d->next;
  1535. X        if (FD_ISSET (d->descriptor, &input_set)) {
  1536. X            d->last_time = now;
  1537. X            if (!process_input (d)) {
  1538. X                shutdownsock (d);
  1539. X                continue;
  1540. X            }
  1541. X        }
  1542. X        if (FD_ISSET (d->descriptor, &output_set)) {
  1543. X            if (!process_output (d)) {
  1544. X            shutdownsock (d);
  1545. X            }
  1546. X        }
  1547. X        }
  1548. X    }
  1549. X    }
  1550. X}
  1551. X
  1552. Xstatic char hostname[128];
  1553. X
  1554. Xstruct descriptor_data *new_connection(int sock)
  1555. X{
  1556. X    int newsock;
  1557. X    struct sockaddr_in addr;
  1558. X    int addr_len;
  1559. X
  1560. X    addr_len = sizeof (addr);
  1561. X    newsock = accept (sock, (struct sockaddr *) & addr, &addr_len);
  1562. X    if (newsock < 0) {
  1563. X    return 0;
  1564. X#ifdef LOCKOUT
  1565. X    } else if(forbidden_site(ntohl(addr.sin_addr.s_addr))) {
  1566. X    writelog("REFUSED CONNECTION from %s(%d) on descriptor %d\n",
  1567. X        addrout(addr.sin_addr.s_addr),
  1568. X        ntohs(addr.sin_port), newsock);
  1569. X    shutdown(newsock, 2);
  1570. X    close(newsock);
  1571. X    errno = 0;
  1572. X    return 0;
  1573. X#endif /* LOCKOUT */
  1574. X    } else {
  1575. X    strcpy (hostname, addrout (addr.sin_addr.s_addr));
  1576. X#ifdef NOISY_LOG
  1577. X    writelog("ACCEPT from %s(%d) on descriptor %d\n",
  1578. X         hostname,
  1579. X         ntohs (addr.sin_port), newsock);
  1580. X#endif NOISY_LOG
  1581. X    return initializesock (newsock, &addr, hostname);
  1582. X    }
  1583. X}
  1584. X
  1585. Xconst char *addrout(long a)
  1586. X{
  1587. X    /* New version: returns host names, not octets.  Uses gethostbyaddr. */
  1588. X    extern char *inet_ntoa(long);
  1589. X    
  1590. X#ifdef HOST_NAME
  1591. X    struct hostent *he;
  1592. X
  1593. X    he = gethostbyaddr(&a,sizeof(a),AF_INET);
  1594. X    if (he) return he->h_name;
  1595. X    else return inet_ntoa(a);
  1596. X#else
  1597. X    return inet_ntoa(a);
  1598. X#endif HOST_NAME
  1599. X}
  1600. X
  1601. X
  1602. Xvoid clearstrings(struct descriptor_data *d)
  1603. X{
  1604. X    if (d->output_prefix) {
  1605. X    FREE(d->output_prefix);
  1606. X    d->output_prefix = 0;
  1607. X    }
  1608. X    if (d->output_suffix) {
  1609. X    FREE(d->output_suffix);
  1610. X    d->output_suffix = 0;
  1611. X    }
  1612. X}
  1613. X
  1614. Xvoid shutdownsock(struct descriptor_data *d)
  1615. X{
  1616. X    if (d->connected) {
  1617. X    writelog("DISCONNECT player %s(%d) %d %s\n",
  1618. X        db[d->player].name, d->player, d->descriptor, d->hostname);
  1619. X#ifdef CONNECT_MESSAGES
  1620. X    announce_disconnect(d->player);
  1621. X#endif CONNECT_MESSAGES
  1622. X    } else {
  1623. X    writelog("DISCONNECT descriptor %d never connected\n",
  1624. X        d->descriptor);
  1625. X    }
  1626. X    clearstrings (d);
  1627. X    shutdown (d->descriptor, 2);
  1628. X    close (d->descriptor);
  1629. X    freeqs (d);
  1630. X    if (d->prev) d->prev->next = d->next; else descriptor_list = d->next;
  1631. X    if (d->next) d->next->prev = d->prev;
  1632. X    FREE (d);
  1633. X    ndescriptors--;
  1634. X}
  1635. X
  1636. Xstruct descriptor_data *initializesock(int s, struct sockaddr_in *a,
  1637. X                       const char *hostname)
  1638. X{
  1639. X    struct descriptor_data *d;
  1640. X
  1641. X    ndescriptors++;
  1642. X    MALLOC(d, struct descriptor_data, 1);
  1643. X    d->descriptor = s;
  1644. X    d->connected = 0;
  1645. X    make_nonblocking (s);
  1646. X    d->output_prefix = 0;
  1647. X    d->output_suffix = 0;
  1648. X    d->output_size = 0;
  1649. X    d->output.head = 0;
  1650. X    d->output.tail = &d->output.head;
  1651. X    d->input.head = 0;
  1652. X    d->input.tail = &d->input.head;
  1653. X    d->raw_input = 0;
  1654. X    d->raw_input_at = 0;
  1655. X    d->quota = COMMAND_BURST_SIZE;
  1656. X    d->last_time = 0;
  1657. X    d->address = *a;            /* added 5/3/90 SCG */
  1658. X    d->hostname = alloc_string(hostname);
  1659. X    if (descriptor_list)
  1660. X        descriptor_list->prev = d;
  1661. X    d->next = descriptor_list;
  1662. X    d->prev = NULL;
  1663. X    descriptor_list = d;
  1664. X    
  1665. X    welcome_user (d);
  1666. X    return d;
  1667. X}
  1668. X
  1669. Xint make_socket(int port)
  1670. X{
  1671. X    int s;
  1672. X    struct sockaddr_in server;
  1673. X    int opt;
  1674. X
  1675. X    s = socket (AF_INET, SOCK_STREAM, 0);
  1676. X    if (s < 0) {
  1677. X    perror ("creating stream socket");
  1678. X    exit (3);
  1679. X    }
  1680. X    opt = 1;
  1681. X    if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR,
  1682. X            (char *) &opt, sizeof (opt)) < 0) {
  1683. X    perror ("setsockopt");
  1684. X    exit (1);
  1685. X    }
  1686. X    server.sin_family = AF_INET;
  1687. X    server.sin_addr.s_addr = INADDR_ANY;
  1688. X    server.sin_port = htons (port);
  1689. X    if (bind (s, (struct sockaddr *) & server, sizeof (server))) {
  1690. X    perror ("binding stream socket");
  1691. X    close (s);
  1692. X    exit (4);
  1693. X    }
  1694. X    listen (s, 5);
  1695. X    return s;
  1696. X}
  1697. X
  1698. Xstruct text_block *make_text_block(const char *s, int n)
  1699. X{
  1700. X    struct text_block *p;
  1701. X
  1702. X    MALLOC(p, struct text_block, 1);
  1703. X    MALLOC(p->buf, char, n);
  1704. X    bcopy (s, p->buf, n);
  1705. X    p->nchars = n;
  1706. X    p->start = p->buf;
  1707. X    p->nxt = 0;
  1708. X    return p;
  1709. X}
  1710. X
  1711. Xvoid free_text_block (struct text_block *t)
  1712. X{
  1713. X    FREE (t->buf);
  1714. X    FREE ((char *) t);
  1715. X}
  1716. X
  1717. Xvoid add_to_queue(struct text_queue *q, const char *b, int n)
  1718. X{
  1719. X    struct text_block *p;
  1720. X
  1721. X    if (n == 0) return;
  1722. X
  1723. X    p = make_text_block (b, n);
  1724. X    p->nxt = 0;
  1725. X    *q->tail = p;
  1726. X    q->tail = &p->nxt;
  1727. X}
  1728. X
  1729. Xint flush_queue(struct text_queue *q, int n)
  1730. X{
  1731. X        struct text_block *p;
  1732. X    int really_flushed = 0;
  1733. X    
  1734. X    n += strlen(flushed_message);
  1735. X
  1736. X    while (n > 0 && (p = q->head)) {
  1737. X        n -= p->nchars;
  1738. X        really_flushed += p->nchars;
  1739. X        q->head = p->nxt;
  1740. X        free_text_block (p);
  1741. X    }
  1742. X    p = make_text_block(flushed_message, strlen(flushed_message));
  1743. X    p->nxt = q->head;
  1744. X    q->head = p;
  1745. X    if (!p->nxt)
  1746. X        q->tail = &p->nxt;
  1747. X    really_flushed -= p->nchars;
  1748. X    return really_flushed;
  1749. X}
  1750. X
  1751. Xint queue_write(struct descriptor_data *d, const char *b, int n)
  1752. X{
  1753. X    int space;
  1754. X
  1755. X    space = MAX_OUTPUT - d->output_size - n;
  1756. X    if (space < 0)
  1757. X        d->output_size -= flush_queue(&d->output, -space);
  1758. X    add_to_queue (&d->output, b, n);
  1759. X    d->output_size += n;
  1760. X    return n;
  1761. X}
  1762. X
  1763. Xint queue_string(struct descriptor_data *d, const char *s)
  1764. X{
  1765. X    return queue_write (d, s, strlen (s));
  1766. X}
  1767. X
  1768. Xint process_output(struct descriptor_data *d)
  1769. X{
  1770. X    struct text_block **qp, *cur;
  1771. X    int cnt;
  1772. X
  1773. X    for (qp = &d->output.head; cur = *qp;) {
  1774. X    cnt = write (d->descriptor, cur -> start, cur -> nchars);
  1775. X    if (cnt < 0) {
  1776. X        if (errno == EWOULDBLOCK)
  1777. X        return 1;
  1778. X        return 0;
  1779. X    }
  1780. X    d->output_size -= cnt;
  1781. X    if (cnt == cur -> nchars) {
  1782. X        if (!cur -> nxt)
  1783. X        d->output.tail = qp;
  1784. X        *qp = cur -> nxt;
  1785. X        free_text_block (cur);
  1786. X        continue;        /* do not adv ptr */
  1787. X    }
  1788. X    cur -> nchars -= cnt;
  1789. X    cur -> start += cnt;
  1790. X    break;
  1791. X    }
  1792. X    return 1;
  1793. X}
  1794. X
  1795. Xvoid make_nonblocking(int s)
  1796. X{
  1797. X    if (fcntl (s, F_SETFL, FNDELAY) == -1) {
  1798. X    perror ("make_nonblocking: fcntl");
  1799. X    panic ("FNDELAY fcntl failed");
  1800. X    }
  1801. X}
  1802. X
  1803. Xvoid freeqs(struct descriptor_data *d)
  1804. X{
  1805. X    struct text_block *cur, *next;
  1806. X
  1807. X    cur = d->output.head;
  1808. X    while (cur) {
  1809. X    next = cur -> nxt;
  1810. X    free_text_block (cur);
  1811. X    cur = next;
  1812. X    }
  1813. X    d->output.head = 0;
  1814. X    d->output.tail = &d->output.head;
  1815. X
  1816. X    cur = d->input.head;
  1817. X    while (cur) {
  1818. X    next = cur -> nxt;
  1819. X    free_text_block (cur);
  1820. X    cur = next;
  1821. X    }
  1822. X    d->input.head = 0;
  1823. X    d->input.tail = &d->input.head;
  1824. X
  1825. X    if (d->raw_input)
  1826. X        FREE (d->raw_input);
  1827. X    d->raw_input = 0;
  1828. X    d->raw_input_at = 0;
  1829. X}
  1830. X
  1831. Xvoid welcome_user(struct descriptor_data *d)
  1832. X{ 
  1833. X    queue_string (d, WELCOME_MESSAGE);
  1834. X# ifdef CONNECT_FILE
  1835. X    do_connect_msg(d, CONNECT_FILE);
  1836. X# endif
  1837. X}
  1838. X
  1839. Xvoid goodbye_user(struct descriptor_data *d)
  1840. X{
  1841. X    write (d->descriptor, LEAVE_MESSAGE, strlen (LEAVE_MESSAGE));
  1842. X}
  1843. X
  1844. Xchar *strsave (const char *s)
  1845. X{
  1846. X    char *p;
  1847. X
  1848. X    MALLOC (p, char, strlen(s) + 1);
  1849. X
  1850. X    if (p)
  1851. X    strcpy (p, s);
  1852. X    return p;
  1853. X}
  1854. X
  1855. Xvoid save_command (struct descriptor_data *d, const char *command)
  1856. X{
  1857. X    add_to_queue (&d->input, command, strlen(command)+1);
  1858. X}
  1859. X
  1860. Xint process_input (struct descriptor_data *d)
  1861. X{
  1862. X    char buf[1024];
  1863. X    int got;
  1864. X    char *p, *pend, *q, *qend;
  1865. X
  1866. X    got = read (d->descriptor, buf, sizeof buf);
  1867. X    if (got <= 0)
  1868. X    return 0;
  1869. X    if (!d->raw_input) {
  1870. X    MALLOC(d->raw_input,char,MAX_COMMAND_LEN);
  1871. X    d->raw_input_at = d->raw_input;
  1872. X    }
  1873. X    p = d->raw_input_at;
  1874. X    pend = d->raw_input + MAX_COMMAND_LEN - 1;
  1875. X    for (q=buf, qend = buf + got; q < qend; q++) {
  1876. X    if (*q == '\n') {
  1877. X        *p = '\0';
  1878. X        if (p > d->raw_input)
  1879. X        save_command (d, d->raw_input);
  1880. X        p = d->raw_input;
  1881. X    } else if (p < pend && isascii (*q) && isprint (*q)) {
  1882. X        *p++ = *q;
  1883. X    }
  1884. X    }
  1885. X    if(p > d->raw_input) {
  1886. X    d->raw_input_at = p;
  1887. X    } else {
  1888. X    FREE(d->raw_input);
  1889. X    d->raw_input = 0;
  1890. X    d->raw_input_at = 0;
  1891. X    }
  1892. X    return 1;
  1893. X}
  1894. X
  1895. Xvoid set_userstring (char **userstring, const char *command)
  1896. X{
  1897. X    if (*userstring) {
  1898. X    FREE(*userstring);
  1899. X    *userstring = 0;
  1900. X    }
  1901. X    while (*command && isascii (*command) && isspace (*command))
  1902. X    command++;
  1903. X    if (*command)
  1904. X    *userstring = strsave (command);
  1905. X}
  1906. X
  1907. Xvoid process_commands(void)
  1908. X{
  1909. X    int nprocessed;
  1910. X    struct descriptor_data *d, *dnext;
  1911. X    struct text_block *t;
  1912. X
  1913. X    do {
  1914. X    nprocessed = 0;
  1915. X    for (d = descriptor_list; d; d = dnext) {
  1916. X        dnext = d->next;
  1917. X        if (d -> quota > 0 && (t = d -> input.head)) {
  1918. X        d -> quota--;
  1919. X        nprocessed++;
  1920. X        if (!do_command (d, t -> start)) {
  1921. X            shutdownsock (d);
  1922. X        } else {
  1923. X            d -> input.head = t -> nxt;
  1924. X            if (!d -> input.head)
  1925. X            d -> input.tail = &d -> input.head;
  1926. X            free_text_block (t);
  1927. X        }
  1928. X        }
  1929. X    }
  1930. X    } while (nprocessed > 0);
  1931. X}
  1932. X
  1933. Xint do_command (struct descriptor_data *d, char *command)
  1934. X{
  1935. X    if (!strcmp (command, QUIT_COMMAND)) {
  1936. X    goodbye_user (d);
  1937. X    return 0;
  1938. X    } else if (!strncmp (command, WHO_COMMAND, strlen(WHO_COMMAND))) {
  1939. X    if (d->output_prefix) {
  1940. X        queue_string (d, d->output_prefix);
  1941. X        queue_write (d, "\n", 1);
  1942. X    }
  1943. X    dump_users (d, command + strlen(WHO_COMMAND));
  1944. X    if (d->output_suffix) {
  1945. X        queue_string (d, d->output_suffix);
  1946. X        queue_write (d, "\n", 1);
  1947. X    }
  1948. X    } else if (d->connected &&
  1949. X           !strncmp (command, PREFIX_COMMAND, strlen (PREFIX_COMMAND))) {
  1950. X#ifdef ROBOT_MODE
  1951. X    if (!Robot(d->player)) { 
  1952. X#ifndef TINKER
  1953. X        notify(d->player,
  1954. X           "Only robots can use OUTPUTPREFIX; contact a Wizard.");
  1955. X#else TINKER
  1956. X        notify(d->player,
  1957. X           "Only robots can use OUTPUTPREFIX; contact a Tinker.");
  1958. X#endif TINKER
  1959. X        return 1;
  1960. X    }
  1961. X    if (!d->connected) return 1;
  1962. X#endif ROBOT_MODE
  1963. X    set_userstring (&d->output_prefix, command+strlen(PREFIX_COMMAND));
  1964. X    } else if (d->connected &&
  1965. X           !strncmp (command, SUFFIX_COMMAND, strlen (SUFFIX_COMMAND))) {
  1966. X#ifdef ROBOT_MODE
  1967. X    if (!Robot(d->player)) { 
  1968. X#ifndef TINKER
  1969. X        notify(d->player,
  1970. X           "Only robots can use OUTPUTSUFFIX; contact a Wizard.");
  1971. X#else TINKER
  1972. X        notify(d->player,
  1973. X           "Only robots can use OUTPUTSUFFIX; contact a Tinker.");
  1974. X#endif TINKER
  1975. X        return 1;
  1976. X    }
  1977. X#endif ROBOT_MODE
  1978. X    set_userstring (&d->output_suffix, command+strlen(SUFFIX_COMMAND));
  1979. X    } else {
  1980. X    if (d->connected) {
  1981. X        if (d->output_prefix) {
  1982. X        queue_string (d, d->output_prefix);
  1983. X        queue_write (d, "\n", 1);
  1984. X        }
  1985. X        process_command (d->player, command);
  1986. X        if (d->output_suffix) {
  1987. X        queue_string (d, d->output_suffix);
  1988. X        queue_write (d, "\n", 1);
  1989. X        }
  1990. X    } else {
  1991. X        check_connect (d, command);
  1992. X    }
  1993. X    }
  1994. X    return 1;
  1995. X}
  1996. X
  1997. Xvoid check_connect (struct descriptor_data *d, const char *msg)
  1998. X{
  1999. X    char command[MAX_COMMAND_LEN];
  2000. X    char user[MAX_COMMAND_LEN];
  2001. X    char password[MAX_COMMAND_LEN];
  2002. X    dbref player;
  2003. X
  2004. X    parse_connect (msg, command, user, password);
  2005. X
  2006. X    if (!strncmp (command, "co", 2)) {
  2007. X    player = connect_player (user, password);
  2008. X    if (player == NOTHING) {
  2009. X        queue_string (d, connect_fail);
  2010. X        writelog("FAILED CONNECT %s on %d %s\n",
  2011. X             user, d->descriptor, d->hostname);
  2012. X    } else {
  2013. X        writelog("CONNECTED %s(%d) on %d %s\n",
  2014. X             db[player].name, player, d->descriptor, d->hostname);
  2015. X        d->connected = 1;
  2016. X        d->connected_at = time(NULL);
  2017. X        d->player = player;
  2018. X
  2019. X        do_motd (player);
  2020. X        do_look_around (player);
  2021. X#ifdef CONNECT_MESSAGES
  2022. X        announce_connect(player);
  2023. X#endif CONNECT_MESSAGES
  2024. X    }
  2025. X    } else if (!strncmp (command, "cr", 2)) {
  2026. X#ifndef REGISTRATION    
  2027. X    player = create_player (user, password);
  2028. X    if (player == NOTHING) {
  2029. X        queue_string (d, create_fail);
  2030. X        writelog("FAILED CREATE %s on %d %s\n",
  2031. X             user, d->descriptor, d->hostname);
  2032. X    } else {
  2033. X        writelog("CREATED %s(%d) on descriptor %d %s\n",
  2034. X             db[player].name, player, d->descriptor, d->hostname);
  2035. X        d->connected = 1;
  2036. X        d->connected_at = time(NULL);
  2037. X        d->player = player;
  2038. X
  2039. X        do_motd (player);
  2040. X        do_look_around (player);
  2041. X#ifdef CONNECT_MESSAGES
  2042. X        announce_connect(player);
  2043. X#endif CONNECT_MESSAGES
  2044. X    }
  2045. X#else
  2046. X    queue_string (d, REGISTER_MESSAGE);
  2047. X#endif REGISTRATION    
  2048. X    } else {
  2049. X    welcome_user (d);
  2050. X    }
  2051. X}
  2052. X
  2053. Xvoid parse_connect (const char *msg, char *command, char *user, char *pass)
  2054. X{
  2055. X    char *p;
  2056. X
  2057. X    while (*msg && isascii(*msg) && isspace (*msg))
  2058. X    msg++;
  2059. X    p = command;
  2060. X    while (*msg && isascii(*msg) && !isspace (*msg))
  2061. X    *p++ = *msg++;
  2062. X    *p = '\0';
  2063. X    while (*msg && isascii(*msg) && isspace (*msg))
  2064. X    msg++;
  2065. X    p = user;
  2066. X    while (*msg && isascii(*msg) && !isspace (*msg))
  2067. X    *p++ = *msg++;
  2068. X    *p = '\0';
  2069. X    while (*msg && isascii(*msg) && isspace (*msg))
  2070. X    msg++;
  2071. X    p = pass;
  2072. X    while (*msg && isascii(*msg) && !isspace (*msg))
  2073. X    *p++ = *msg++;
  2074. X    *p = '\0';
  2075. X}
  2076. X
  2077. Xvoid close_sockets(void)
  2078. X{
  2079. X    struct descriptor_data *d, *dnext;
  2080. X
  2081. X    for (d = descriptor_list; d; d = dnext) {
  2082. X    dnext = d->next;
  2083. X    write (d->descriptor, shutdown_message, strlen (shutdown_message));
  2084. X    if (shutdown (d->descriptor, 2) < 0)
  2085. X        perror ("shutdown");
  2086. X    close (d->descriptor);
  2087. X    }
  2088. X    close (sock);
  2089. X}
  2090. X
  2091. Xvoid emergency_shutdown(void)
  2092. X{
  2093. X    close_sockets();
  2094. X}
  2095. X
  2096. Xvoid boot_off(dbref player)
  2097. X{
  2098. X    struct descriptor_data *d, *dnext;
  2099. X    for (d = descriptor_list; d; d = dnext) {
  2100. X      dnext = d->next;
  2101. X      if (d->connected && d->player == player) {
  2102. X          process_output(d);
  2103. X      shutdownsock(d);
  2104. X      }
  2105. X    }
  2106. X}
  2107. X
  2108. Xint bailout (int sig, int code, struct sigcontext *scp)
  2109. X{
  2110. X    long *ptr;
  2111. X    int i;
  2112. X    
  2113. X    writelog("BAILOUT: caught signal %d code %d\n", sig, code);
  2114. X    ptr = (long *) scp;
  2115. X    for (i=0; i<sizeof(struct sigcontext); i++)
  2116. X    writelog("  %08lx\n", *ptr);
  2117. X    panic("PANIC on spurious signal");
  2118. X    _exit(7);
  2119. X    return 0;
  2120. X}
  2121. X
  2122. Xint sigshutdown (int sig, int code, struct sigcontext *scp)
  2123. X{
  2124. X    writelog("SHUTDOWN: on signal %d code %d\n", sig, code);
  2125. X    shutdown_flag = 1;
  2126. X    return 0;
  2127. X}
  2128. X
  2129. X#ifdef DETACH
  2130. Xint logsynch (int sig, int code, struct sigcontext *scp)
  2131. X{
  2132. X    freopen(logfile, "a", stderr);
  2133. X    setbuf(stderr, NULL);
  2134. X    writelog("log file reopened\n");
  2135. X    return 0;
  2136. X}
  2137. X#endif DETACH    
  2138. X
  2139. Xvoid dump_users(struct descriptor_data *e, char *user)
  2140. X{
  2141. X    struct descriptor_data *d;
  2142. X    long now;
  2143. X    char buf[1024];
  2144. X    int wizard;
  2145. X    int reversed, tabular;
  2146. X
  2147. X    while (*user && isspace(*user)) user++;
  2148. X    if (!*user) user = NULL;
  2149. X
  2150. X    reversed = e->connected && Flag(e->player,REVERSED_WHO);
  2151. X    tabular = e->connected && Flag(e->player,TABULAR_WHO);
  2152. X
  2153. X    (void) time (&now);
  2154. X    queue_string(e,
  2155. X         tabular ? "Player Name          On For Idle\n" : "Current Players:\n");
  2156. X#ifdef GOD_MODE
  2157. X    wizard = e->connected && God(e->player);
  2158. X#else GOD_MODE    
  2159. X    wizard = e->connected && Wizard(e->player);
  2160. X#endif GOD_MODE
  2161. X
  2162. X    d = descriptor_list;
  2163. X    
  2164. X    if (reversed)
  2165. X    while (d && d->next) d = d->next;
  2166. X
  2167. X    while (d) {
  2168. X    if (d->connected &&
  2169. X        (!user || string_prefix(db[d->player].name, user))) {
  2170. X        if (tabular) {
  2171. X        sprintf(buf,"%-16s %10s %4s",
  2172. X            db[d->player].name,
  2173. X            time_format_1(now - d->connected_at),
  2174. X            time_format_2(now - d->last_time));
  2175. X        if (wizard) 
  2176. X            sprintf(buf+strlen(buf),
  2177. X                " %s", d->hostname);
  2178. X        } else {
  2179. X        sprintf(buf,
  2180. X            "%s idle %d seconds",
  2181. X            db[d->player].name,
  2182. X            now - d->last_time);
  2183. X        if (wizard) 
  2184. X            sprintf(buf+strlen(buf),
  2185. X                " from host %s", d->hostname);
  2186. X        }
  2187. X        strcat(buf,"\n");
  2188. X        queue_string (e, buf);
  2189. X    }
  2190. X    if (reversed) d = d->prev; else d = d->next;
  2191. X    }
  2192. X}
  2193. X
  2194. Xchar *time_format_1(long dt)
  2195. X{
  2196. X    register struct tm *delta;
  2197. X    static char buf[64];
  2198. X    
  2199. X    delta = gmtime(&dt);
  2200. X    if (delta->tm_yday > 0)
  2201. X    sprintf(buf, "%dd %02d:%02d",
  2202. X        delta->tm_yday, delta->tm_hour, delta->tm_min);
  2203. X    else
  2204. X    sprintf(buf, "%02d:%02d",
  2205. X        delta->tm_hour, delta->tm_min);
  2206. X    return buf;
  2207. X}
  2208. X
  2209. Xchar *time_format_2(long dt)
  2210. X{
  2211. X    register struct tm *delta;
  2212. X    static char buf[64];
  2213. X    
  2214. X    delta = gmtime(&dt);
  2215. X    if (delta->tm_yday > 0)
  2216. X    sprintf(buf, "%dd", delta->tm_yday);
  2217. X    else if (delta->tm_hour > 0)
  2218. X    sprintf(buf, "%dh", delta->tm_hour);
  2219. X    else if (delta->tm_min > 0)
  2220. X    sprintf(buf, "%dm", delta->tm_min);
  2221. X    else
  2222. X    sprintf(buf, "%ds", delta->tm_sec);
  2223. X    return buf;
  2224. X}
  2225. X
  2226. X#ifdef CONNECT_MESSAGES
  2227. Xvoid announce_connect(dbref player)
  2228. X{
  2229. X    dbref loc;
  2230. X    char buf[BUFFER_LEN];
  2231. X
  2232. X    if ((loc = getloc(player)) == NOTHING) return;
  2233. X    if (Dark(player) || Dark(loc)) return;
  2234. X
  2235. X    sprintf(buf, "%s has connected.", db[player].name);
  2236. X
  2237. X    notify_except(db[loc].contents, player, buf);
  2238. X}
  2239. X
  2240. Xvoid announce_disconnect(dbref player)
  2241. X{
  2242. X    dbref loc;
  2243. X    char buf[BUFFER_LEN];
  2244. X
  2245. X    if ((loc = getloc(player)) == NOTHING) return;
  2246. X    if (Dark(player) || Dark(loc)) return;
  2247. X
  2248. X    sprintf(buf, "%s has disconnected.", db[player].name);
  2249. X
  2250. X    notify_except(db[loc].contents, player, buf);
  2251. X}
  2252. X#endif CONNECT_MESSAGES
  2253. Xint do_connect_msg(struct descriptor_data * d, const char *filename)
  2254. X{
  2255. X  FILE           *f;
  2256. X  char            buf[BUFFER_LEN];
  2257. X  char           *p;
  2258. X
  2259. X  if ((f = fopen(filename, "r")) == NULL)
  2260. X  {
  2261. X    return (0);
  2262. X  } else
  2263. X  {
  2264. X    while (fgets(buf, sizeof buf, f))
  2265. X    {
  2266. X      queue_string(d, (char *)buf);
  2267. X
  2268. X    }
  2269. X    fclose(f);
  2270. X    return (1);
  2271. X  }
  2272. X}
  2273. END_OF_FILE
  2274. if test 24677 -ne `wc -c <'oldinterface.c'`; then
  2275.     echo shar: \"'oldinterface.c'\" unpacked with wrong size!
  2276. fi
  2277. # end of 'oldinterface.c'
  2278. fi
  2279. echo shar: End of archive 8 \(of 10\).
  2280. cp /dev/null ark8isdone
  2281. MISSING=""
  2282. for I in 1 2 3 4 5 6 7 8 9 10 ; do
  2283.     if test ! -f ark${I}isdone ; then
  2284.     MISSING="${MISSING} ${I}"
  2285.     fi
  2286. done
  2287. if test "${MISSING}" = "" ; then
  2288.     echo You have unpacked all 10 archives.
  2289.     echo ">>> now type 'sh joinspl.sh'"
  2290.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2291. else
  2292.     echo You still need to unpack the following archives:
  2293.     echo "        " ${MISSING}
  2294. fi
  2295. ##  End of shell archive.
  2296. exit 0
  2297.